
#include "StdAfx.h"
#include "C7zMgr.h"
#include <tchar.h>

extern const GUID CLSID_CFormat7z;
#define CLSID_Format CLSID_CFormat7z

using namespace NWindows;
using namespace NFile;
using namespace NDir;

STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject);

C7zMgrArchive::C7zMgrArchive(void)
{
	m_openMode = FCreate;

	CreateObject(&CLSID_Format, &IID_IOutArchive, (void **)&m_ptrOutArchive);
	if ( m_ptrOutArchive )
	{
		m_ptrOutArchive->QueryInterface(IID_IInArchive,(void**)&m_ptrInArchive);
	}
}
C7zMgrArchive::~C7zMgrArchive(void)
{
	Close();
	if ( m_ptrInArchive )
	{
		m_ptrInArchive->Release();
	}
	if ( m_ptrOutArchive )
	{
		m_ptrOutArchive->Release();
	}
}

bool C7zMgrArchive::Open(const wchar_t* chPath,long iOffset/* = 0*/)
{
	if ( m_ptrInArchive )
	{
		m_FsPath = chPath;
		m_iOffSet= iOffset;
		//如果文件存在则打开，否则创建
		CInFileStream *fileSpec = new CInFileStream;
		CMyComPtr<IInStream> ptrpInstream = fileSpec;
		if ( !fileSpec->Open(chPath) )
		{
			m_openMode = FCreate;
		}
		else
		{
			m_openMode = FUpdate;
			UInt64 cur = 0;
			fileSpec->Seek(iOffset,STREAM_SEEK_SET,&cur);
			CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
			CMyComPtr<IArchiveOpenCallback> ptrOpenCallback = openCallbackSpec;

			const UInt64 scanSize = 0;
			if (m_ptrInArchive->Open(ptrpInstream, &scanSize,ptrOpenCallback) != S_OK)
			{
				return false;
			}
		}
		return true;
	}
	return false;
}

void C7zMgrArchive::Close()
{
	if ( m_ptrInArchive )
	{
		m_ptrInArchive->Close();
	}
}

int C7zMgrArchive::GetFileNum()
{
	if ( m_ptrInArchive )
	{
		UInt32 numItems = 0;
		m_ptrInArchive->GetNumberOfItems(&numItems);
		return numItems;
	}
	return -1;
}

bool C7zMgrArchive::GetFileName(int iIndex,_7zFileInfo& _info)
{
	if ( m_ptrInArchive )
	{
		NCOM::CPropVariant prop;
		m_ptrInArchive->GetProperty(iIndex,kpidIsDir,&prop);
		_info.isDir = prop.boolVal != VARIANT_FALSE;

		m_ptrInArchive->GetProperty(iIndex,kpidPath,&prop);
		if (prop.vt == VT_BSTR)
			MyStringCopy(_info.name,prop.bstrVal);

		return true;
	}
	return false;
}
bool C7zMgrArchive::ExtractFile(int iIndex/* = -1*/,const wchar_t* _path/* = NULL*/, pfnGetExtractPath pfn/* = NULL*/,void* param/* = NULL*/)	
{
	if ( m_ptrInArchive )
	{	
		HRESULT result = S_OK;
		CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
		CMyComPtr<IArchiveExtractCallback> ptrextractCallback = extractCallbackSpec;
		extractCallbackSpec->m_PasswordIsDefined = false;
		extractCallbackSpec->m_pfn = pfn;
		extractCallbackSpec->m_param = param;
		extractCallbackSpec->Init(m_ptrInArchive, _path == NULL ? L"" : _path);
			
		if ( iIndex == -1 )
		{
			result = m_ptrInArchive->Extract(NULL,-1, false, ptrextractCallback);
		}
		else
		{
			UInt32 index[] = {iIndex};
			result = m_ptrInArchive->Extract(index,1, false, ptrextractCallback);
		}
		UInt64 iErrNum = extractCallbackSpec->m_NumErrors;
		return result == S_OK;
	}
	return false;
}

bool C7zMgrArchive::ArchiveFiles(const wchar_t* _path)
{
	if ( m_ptrOutArchive )
	{
		CObjectVector<CDirItem> dirItems;
		NFind::CFileInfo fi;
		CDirItem di;

		//添加新增文件
		FString root = _path;
		FString path = _path;
		if ( fi.Find(path)) 
		{
			di.Attrib = fi.Attrib;
			di.Size = fi.Size;
			di.CTime = fi.CTime;
			di.ATime = fi.ATime;
			di.MTime = fi.MTime;
			di.FullPath = path;
			di.Name = fi.Name;
			if ( fi.IsDir() )
			{
				root = root.Left(path.Len()-di.Name.Len());
				GetEnumFile(root,path,dirItems);
			}
			dirItems.Add(di);
		}
		return SaveArchive(dirItems);
	}
	return false;
}

bool C7zMgrArchive::SaveArchive(CObjectVector<CDirItem>& object)
{
	HRESULT result = S_OK;
	{
		//创建临时文件
		CMyComPtr<IOutStream> outStream = NULL;
		COutFileStream *outFileStreamSpec = new COutFileStream;
		outStream = outFileStreamSpec;

		FString strPath = FUpdate == m_openMode ? GetTmpFile() : m_FsPath;
		if (!outFileStreamSpec->Create( strPath, true))
		{
			return false;
		}

		CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
		CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec);
		updateCallbackSpec->Init(&object);
		result = m_ptrOutArchive->UpdateItems(outStream, object.Size(), updateCallback);
		updateCallbackSpec->Finilize();
		int iFailSize = updateCallbackSpec->m_FailedFiles.Size();
	}

	if ( FUpdate == m_openMode)
	{
		SaveTmpFile(S_OK == result);
	}
	ReOpenFile();
	return S_OK == result;
}
FString C7zMgrArchive::GetTmpFile()
{
	return m_FsPath + L".tmp.7z";
}
bool C7zMgrArchive::ReOpenFile()
{
	Close();
	return Open(m_FsPath,m_iOffSet);
}
void C7zMgrArchive::SaveTmpFile(bool bOK)
{
	Close();
	FString strPath = GetTmpFile();
	BOOL bTrue = MyMoveFile(strPath,m_FsPath);
	return;
}
void C7zMgrArchive::GetEnumFile(const FString& root,FString path,CObjectVector<CDirItem>& object)
{
	NFind::CFileInfo fi;
	CDirItem di;

	NFind::CEnumerator enumfile(path+L"/*.*");
	while(enumfile.Next(fi))
	{
		di.Attrib = fi.Attrib;
		di.Size = fi.Size;
		di.CTime = fi.CTime;
		di.ATime = fi.ATime;
		di.MTime = fi.MTime;
		di.FullPath = path + L"/" + fi.Name;
		di.Name = di.FullPath.Mid(root.Len(),di.FullPath.Len() - root.Len());
		if ( fi.IsDir() )
		{
			GetEnumFile(root,path + L"/" + fi.Name ,object);	
		}
		object.Add(di);
	}
}

IVrvBase *CreateIVrvObj(int iID)
{
	if( iID == IID_I7zMgrArchive )
	{
		return new C7zMgrArchive();
	}
}